package com.onpositive.realmview.queryeditor;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.commands.operations.ObjectUndoContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.operations.RedoActionHandler;
import org.eclipse.ui.operations.UndoActionHandler;
import org.eclipse.ui.part.DrillDownAdapter;

import com.onpositive.commons.elements.AbstractUIElement;
import com.onpositive.commons.elements.Container;
import com.onpositive.commons.elements.SWTEventListener;
import com.onpositive.commons.ui.appearance.OneElementOnLineLayouter;
import com.onpositive.commons.ui.dialogs.ElementDialog;
import com.onpositive.queryeditor.util.DndUtil;
import com.onpositive.realmview.AbstractRealmView;
import com.onpositive.realmview.IRealmView;
import com.onpositive.realmview.model.ColumnConfiguration;
import com.onpositive.realmview.model.ICanDelete;
import com.onpositive.realmview.model.IHasPublicUrl;
import com.onpositive.realmview.model.IPartWithCopies;
import com.onpositive.realmview.model.ITemplateCustomizer;
import com.onpositive.realmview.model.IViewGrouping;
import com.onpositive.realmview.model.IWorkingCopy;
import com.onpositive.realmview.model.filtering.BooleanFilter;
import com.onpositive.realmview.queryeditor.actions.DeleteAction;
import com.onpositive.realmview.queryeditor.actions.FilterBySelectionAction;
import com.onpositive.realmview.queryeditor.actions.FilterExceptSelectionAction;
import com.onpositive.semantic.common.ui.roles.ImageManager;
import com.onpositive.semantic.common.ui.roles.WidgetRegistry;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.semantic.model.api.property.IPropertyProvider;
import com.onpositive.semantic.model.binding.Binding;
import com.onpositive.semantic.model.realm.IModifiableRealm;
import com.onpositive.semantic.model.realm.Realm;
import com.onpositive.semantic.model.ui.property.editors.ButtonSelector;
import com.onpositive.semantic.model.ui.property.editors.DisposeBindingListener;
import com.onpositive.semantic.model.ui.property.editors.OneLineTextElement;
import com.onpositive.semantic.model.ui.property.editors.structured.ListEnumeratedValueSelector;
import com.onpositive.semantic.model.ui.property.editors.structured.UniversalLabelProvider;
import com.onpositive.semantic.model.ui.property.editors.structured.columns.Column;
import com.onpositive.semantic.model.ui.property.editors.structured.columns.ColumnEditingSupport;
import com.onpositive.semantic.model.ui.viewer.structured.CustomColumnViewerTooltipSupport;
import com.onpositive.viewer.extension.coloring.ColoredViewersManager;


public abstract class ExtendedQueryEditor extends QueryEditorPart implements
		ITemplateCustomizer, IPartWithCopies {

	public static class PasteEditorActionDelegate implements
			IEditorActionDelegate {

		private TreeViewer viewer;
		private ExtendedQueryEditor editor;

		public void setActiveEditor(IAction action, IEditorPart targetEditor) {
			if (targetEditor instanceof ExtendedQueryEditor) {
				viewer = ((ExtendedQueryEditor) targetEditor).getViewer();
				editor = ((ExtendedQueryEditor) targetEditor);
			}
		}

		public void run(IAction action) {
		}

		public void selectionChanged(IAction action, ISelection selection) {
			// TODO Auto-generated method stub

		}

	}

	public static class CopyEditorActionDelegate implements
			IEditorActionDelegate {

		private TreeViewer viewer;
		private ExtendedQueryEditor editor;

		public void setActiveEditor(IAction action, IEditorPart targetEditor) {
			if (targetEditor == null) {
				return;
			}
			viewer = ((ExtendedQueryEditor) targetEditor).getViewer();
			editor = ((ExtendedQueryEditor) targetEditor);
			return;

		}

		public void run(IAction action) {
			ISelection s = viewer.getSelection();
			if (s instanceof IStructuredSelection) {
				StringWriter out = new StringWriter();
				PrintWriter w = new PrintWriter(out);
				IBaseLabelProvider ibl = viewer.getLabelProvider();
				if (ibl instanceof ILabelProvider) {
					ILabelProvider ilb = (ILabelProvider) ibl;

					Control c = viewer.getControl();
					IStructuredSelection ts = (IStructuredSelection) s;
					Object[] paths = ts.toArray();
					List ppp = Arrays.asList(paths);

					if (c instanceof Tree) {
						Tree tr = (Tree) c;
						TreeItem[] items = tr.getItems();
						for (TreeItem item : items) {
							processItem(w, ilb, ppp, item);
						}
					} else {
						for (Object p : paths) {
							String tmp = ilb.getText(p);
							w.println(tmp);
						}
					}
				}
				Clipboard clip = editor.getClipboard();

				if (clip != null && !clip.isDisposed()) {
					TextTransfer transfer = TextTransfer.getInstance();
					Transfer[] tr = new Transfer[] { transfer };
					String string = out.toString();
					if (string.length() == 0) {
						return;
					}
					clip.setContents(new String[] { string }, tr);
				}
				return;
			}
		}

		private void processItem(PrintWriter w, ILabelProvider ilb, List ppp,
				TreeItem item) {
			Object data = item.getData();
			if (data != null && ppp.contains(data)) {
				String tmp = ilb.getText(data);
				w.println(tmp);
			}
			TreeItem[] itemss = item.getItems();
			if (itemss != null) {
				for (TreeItem itemm : itemss) {
					processItem(w, ilb, ppp, itemm);
				}
			}
		}

		public void selectionChanged(IAction action, ISelection selection) {
			return;
		}

	}

	protected class ChangeNodeGroupingAction extends Action {
		GroupNode groupNode;
		IViewGrouping viewGrouping;
		StructuredViewer viewer;
		IRealmView realmView;
		IEditorPart parentPart;

		public ChangeNodeGroupingAction(GroupNode groupNode,
				IViewGrouping viewGrouping, StructuredViewer viewer,
				IEditorPart parentPart) {
			super("", Action.AS_CHECK_BOX);
			this.groupNode = groupNode;
			this.viewGrouping = viewGrouping;
			this.viewer = viewer;
			this.parentPart = parentPart;
		}

		public void run() {
			groupNode.setChildrenGrouping(viewGrouping);
			if (viewGrouping != null)
				groupNode.getRealmView().put(groupNode.getLongString(),
						viewGrouping.getId());
			else
				groupNode.getRealmView().getSettings()
						.remove(groupNode.getLongString());
			viewer.refresh();
			if (parentPart instanceof ExtendedQueryEditor)
				((ExtendedQueryEditor) parentPart).fireDirty();
		}

	}

	protected static final int EXPAND_ITEM_COUNT = 5;

	protected static final String REQUIRE_COMMENT_ID = "REQUIRE_COMMENT";

	int count = 0;

	int lastSaveCount = 0;

	private boolean toolbarCreated;

	public boolean isToolbarCreated() {
		return toolbarCreated;
	}

	public void setToolbarCreated(boolean needToolbar) {
		this.toolbarCreated = needToolbar;
	}

	private TreeViewer viewer;

	ArrayList<Column> activeColumns = new ArrayList<Column>();

	private GroupingContentProvider provider;

	private Clipboard clipboard;

	private TreeColumn titleColumn;

	private DrillDownAdapter drillDown;

	public TreeViewer getViewer() {
		return viewer;
	}

	// public void

	public static interface IInsertStringCallBack {
		void handle(String handled);
	}

	public void doSaveAs() {
		showInsertStringDialog(new IInsertStringCallBack() {

			public void handle(String name) {
				saveRealm(name);
			}
		});
		super.doSaveAs();
	}

	/**
	 * 
	 */
	public void showInsertStringDialog(final IInsertStringCallBack cb) {
		final IRealmView v = (IRealmView) copy;
		IModifiableRealm<IRealmView> views = v.getParent().views();

		final Binding b = new Binding("");
		b.setRequired(true);
		b.setAutoCommit(true);
		b.setName("New Name:");
		Container c = new Container();
		c.setLayoutManager(new OneElementOnLineLayouter());
		c.add(new OneLineTextElement<String>(b));
		Container c1 = new Container();
		c.add(c1);
		ButtonSelector element = new ButtonSelector();
		element.setText("Ok");

		c1.add(element);
		ButtonSelector element2 = new ButtonSelector();
		c1.add(element2);
		element2.setText("Cancel");
		DisposeBindingListener.linkBindingLifeCycle(b, c);
		final ElementDialog elementDialog = new ElementDialog(b, c,
				"Save view as:", "");

		element.addListener(SWT.Selection, new SWTEventListener<Button>() {

			public void handleEvent(AbstractUIElement<Button> element,
					Event event) {
				String name = (String) b.getValue();
				if (cb != null) {
					cb.handle(name);
				}
				elementDialog.close();
			}

		});
		element2.addListener(SWT.Selection, new SWTEventListener<Button>() {

			public void handleEvent(AbstractUIElement<Button> element,
					Event event) {
				elementDialog.close();
			}
		});
		elementDialog.open();
	}

	/**
	 * 
	 */
	public void showListStringDialog(final IInsertStringCallBack cb,
			List<String> els) {
		final IRealmView v = (IRealmView) copy;
		IModifiableRealm<IRealmView> views = v.getParent().views();

		Container c = new Container();
		c.setLayoutManager(new OneElementOnLineLayouter());
		final ListEnumeratedValueSelector<String> controll = new ListEnumeratedValueSelector<String>();
		controll.setText("Please select cofiguration:");
		controll.setRealm(new Realm<String>(els));

		c.add(controll);
		Container c1 = new Container();
		c.add(c1);
		ButtonSelector element = new ButtonSelector();
		element.setText("Ok");

		c1.add(element);
		ButtonSelector element2 = new ButtonSelector();
		c1.add(element2);
		element2.setText("Cancel");

		final ElementDialog elementDialog = new ElementDialog(new Binding(""),
				c, "Saved configs:", "");

		element.addListener(SWT.Selection, new SWTEventListener<Button>() {

			public void handleEvent(AbstractUIElement<Button> element,
					Event event) {
				IStructuredSelection selection = controll.getSelection();
				if (selection != null) {
					Object fe = selection.getFirstElement();
					if (fe != null) {
						String name = fe.toString();
						if (cb != null) {
							cb.handle(name);
						} else {
							alert("Selection should not be empty");
						}
					} else {
						alert("Selection should not be empty");
					}
				} else {
					alert("Selection should not be empty");
				}
				elementDialog.close();
			}

		});
		element2.addListener(SWT.Selection, new SWTEventListener<Button>() {

			public void handleEvent(AbstractUIElement<Button> element,
					Event event) {
				elementDialog.close();
			}
		});
		elementDialog.open();
	}

	/**
	 * @param v
	 * @param b
	 * @param elementDialog
	 */
	protected void saveRealm(String name) {
		final IRealmView v = (IRealmView) copy;
		v.setName(name);
		v.getParent().views().add(v);
		copy = v.clone();
		setPartName(v.getName());
		setInput(new QueryInput(v));
		firePropertyChange(PROP_INPUT);
	}

	public void doSave(IProgressMonitor monitor) {

		IRealmView query = ((QueryInput) getEditorInput()).getView();
//		boolean f = tryToLoadOnServer(query);
//		if (!f) {
//			return;
//		}
		com.onpositive.realmview.progress.IProgressMonitor innerMonitor = createInnerMonitor(monitor);

		copy.setName(query.getName());
		query.updateFrom(copy);
		count++;

		copy.commit(innerMonitor, true);

		firePropertyChange(PROP_DIRTY);
	}

	protected com.onpositive.realmview.progress.IProgressMonitor createInnerMonitor(
			IProgressMonitor monitor) {
		// TODO Auto-generated method stub
		return null;
	}

//	/**
//	 * @param query
//	 */
//	protected boolean tryToLoadOnServer(IRealmView query) {
//
//		boolean flg = ((AbstractRealmView) copy).isSyncViewWithPrivateServer()
//				&& !((AbstractRealmView) query).isSyncViewWithPrivateServer();
//
//		if (flg) {
//			return true;
//		}
//
//		boolean enabled = false;
//		IHasViews<?> p = query.getParent();
//		PrivateServiceConnector conn = null;
//		SyncingRichDocumentService syncService = null;
//		if (p != null) {
//			IHasTemplates clz = p.getAdapter(IHasTemplates.class);
//			if (clz instanceof SyncingRichDocumentService) {
//
//				syncService = (SyncingRichDocumentService) clz;
//				conn = syncService.getPrivateConnector();
//				if (conn != null && conn.isEnabled()) {
//					enabled = true;
//				}
//			}
//		}
//
//		if (!enabled) {
//			((AbstractRealmView) query).setSyncViewWithPrivateServer(enabled);
//		}
//
//		if (((AbstractRealmView) query).isSyncViewWithPrivateServer()) {
//			if (conn != null) {
//				try{
//				boolean flg1 = conn.storeViewOnServer((AbstractRealmView) copy,
//						syncService);
//				return flg1;
//				}catch (IllegalStateException e) {
//					MessageDialog.openError(Display.getCurrent().getActiveShell(),"Team server error","Team server is not enabled for this repository");
//					return false;
//				}
//			}
//		}
//		return true;
//	}

	protected void persistCopySettings() {
		//Do nothing; Override if needed
	}

	public void refreshViewer() {
		TreePath[] expandedTreePaths = viewer.getExpandedTreePaths();
		if (viewer.getInput() instanceof GroupNode) {
			provider.refreshNode();
		} else {
			viewer.refresh(true);
			TreePath[] l2 = viewer.getExpandedTreePaths();
			HashSet<TreePath> p = new HashSet<TreePath>();
			p.addAll(Arrays.asList(expandedTreePaths));
			p.addAll(Arrays.asList(l2));
			viewer.setExpandedTreePaths(p.toArray(new TreePath[p.size()]));
			viewer.getControl().redraw();
		}
	}

	public Column getColumn(int columnIndex) {
		return activeColumns.get(columnIndex);
	}

	public Clipboard getClipboard() {
		return clipboard;
	}

	public void dispose() {
		super.dispose();
		if (clipboard != null)
			clipboard.dispose();
	}

	private Composite headerComp;

	public void createPartControl(Composite parent) {
		final boolean standalone = Platform.getPreferencesService().getBoolean(
				"com.onpositive.wiki.rcp", "STANDALONE", false, null);
		if (!standalone && !toolbarCreated) {
			Composite p = new Composite(parent, SWT.None);
			final GridLayout layout = new GridLayout(1, false);
			layout.horizontalSpacing = 0;
			layout.verticalSpacing = 0;
			layout.marginWidth = 0;
			layout.marginHeight = 0;
			p.setLayout(layout);

			headerComp = new Composite(p, SWT.NONE);
			headerComp.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true,
					false));

			final Composite body = new Composite(p, SWT.NONE);
			body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
			createEditor(body);
			createToolBar(headerComp);
		} else {
			createEditor(parent);
		}

	}

	private void createToolBar(Composite parent) {
		// com.onpositive.wiki.ui.editorToolBarCreator
		ToolBar tb = new ToolBar(parent, SWT.HORIZONTAL | SWT.FLAT);
		tb.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true));
		final IConfigurationElement[] element = Platform.getExtensionRegistry()
				.getConfigurationElementsFor(
						"com.onpositive.wiki.ui.editorToolBarCreator");
		for (IConfigurationElement e : element) {
			String vAttr = e.getAttribute("editor");
			if (vAttr != null && vAttr.equals("com.onpositive.query.editor")) {
				try {
					Object ext = e.createExecutableExtension("class");
					if (ext instanceof IEditorToolbarCreator) {
						final ToolBarManager manager = new ToolBarManager(tb);

						((IEditorToolbarCreator) ext).createToolbar(manager,
								this);
						tb.layout(true, true);
					}
				} catch (CoreException e1) {
					e1.printStackTrace();
				}

			}
		}
	}

	protected void createEditor(Composite parent) {
		clipboard = new Clipboard(parent.getDisplay());
		viewer = new TreeViewer(parent, SWT.FULL_SELECTION | SWT.MULTI) {

			protected TreePath getTreePathFromItem(Item item) {
				if (item.getData() == null) {
					return new TreePath(new Object[] {});
				}
				return super.getTreePathFromItem(item);
			}

			protected void preservingSelection(Runnable updateCode) {
				ISelection oldSelection = null;
				try {
					// preserve selection
					oldSelection = getSelection();

					// perform the update
					updateCode.run();

				} finally {
					oldSelection = convertSelection(oldSelection);
					// restore selection
					setSelectionToWidget(oldSelection, true);

					// send out notification if old and new differ
					ISelection newSelection = getSelection();
					if (!newSelection.equals(oldSelection)) {
						handleInvalidSelection(oldSelection, newSelection);
					}
				}
			}

		};
		viewer.setUseHashlookup(true);
		CustomColumnViewerTooltipSupport customColumnViewerTooltipSupport = new CustomColumnViewerTooltipSupport(
				viewer, null);
		customColumnViewerTooltipSupport.setHideOnMouseDown(false);
		provider = new GroupingContentProvider();
		provider.setFirstGrouping(copy.getCurrentGrouping());
		provider.setSecondGrouping(copy.getSecondLevelGrouping());

		viewer.setContentProvider(provider);
		if (getEditorInput() != null) {
			setPartName(getEditorInput().getName());
		}
		drillDown = new DrillDownAdapter(viewer) {

			public void goInto() {
				super.goInto();
				updatePartTitle();
				firePropertyChange(PROP_DIRTY);
			}

			public void goBack() {
				super.goBack();
				updatePartTitle();
				firePropertyChange(PROP_DIRTY);
			}

			public void goHome() {
				super.goHome();
				updatePartTitle();
				firePropertyChange(PROP_DIRTY);
			}

		};
		activeColumns.add(new Column("Title", "title"));
		Transfer[] transferTypes = new Transfer[] { LocalSelectionTransfer
				.getTransfer() };
		viewer.addDragSupport(DND.DROP_MOVE, transferTypes,
				new DragSourceAdapter((ColumnViewer) this.viewer));
		viewer.addDropSupport(DND.DROP_MOVE, transferTypes,
				new DropMoveAdapter((ColumnViewer) viewer));
		IEditorSite editorSite = getEditorSite();
		if (editorSite != null) {
			final UndoActionHandler undoActionHandler = new UndoActionHandler(
					this.getEditorSite(), new ObjectUndoContext(this));
			undoActionHandler
					.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO);
			customizeActionBars(undoActionHandler);
		}

		UniversalLabelProvider<Object> labelProvider = createLabelProvider(
				this);
		titleColumn = new TreeColumn(viewer.getTree(), SWT.LEFT);
		titleColumn.setText("Title");
		titleColumn.addSelectionListener(new SelectionListener() {

			public void widgetSelected(SelectionEvent e) {
				if (viewer.getTree().getSortColumn() == titleColumn) {
					setCurrentSorting(null,
							viewer.getTree().getSortDirection() == SWT.UP);
				} else {
					setCurrentSorting(null, false);
				}
			}

			public void widgetDefaultSelected(SelectionEvent e) {

			}
		});
		if (currentSorting == null) {
			viewer.getTree().setSortColumn(titleColumn);
			viewer.getTree().setSortDirection(sortInverse ? SWT.DOWN : SWT.UP);
		}
		viewer.setLabelProvider(labelProvider);
		MenuManager pManager = new MenuManager();
		pManager.addMenuListener(new IMenuListener() {

			public void menuAboutToShow(IMenuManager manager) {
				manager.add(new Action("Open", Action.AS_PUSH_BUTTON) {
					public void run() {
						Binding bnd = new Binding(
								((IStructuredSelection) viewer.getSelection())
										.getFirstElement());
						WidgetRegistry.getInstance().showWidget(bnd);
						bnd.dispose();
					}
				});
				final IStructuredSelection selection1 = (IStructuredSelection) viewer
						.getSelection();
				manager.add(new Separator());
				if (selection1.getFirstElement() instanceof GroupNode) {
					drillDown.addNavigationActions(manager);
				} else {
					Object input = viewer.getInput();
					if (input instanceof GroupNode) {
						try {
							{
								Field declaredField = DrillDownAdapter.class
										.getDeclaredField("backAction");
								declaredField.setAccessible(true);
								IAction object = (IAction) declaredField
										.get(drillDown);
								if (object == null) {
									drillDown
											.addNavigationActions(new MenuManager());
								}
								object = (IAction) declaredField.get(drillDown);
								manager.add(object);
							}
							Field declaredField = DrillDownAdapter.class
									.getDeclaredField("homeAction");
							declaredField.setAccessible(true);
							IAction object = (IAction) declaredField
									.get(drillDown);
							manager.add(object);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
				manager.add(new Separator());
				IAction copyAction = new Action("Copy", Action.AS_PUSH_BUTTON) {
					public void run() {
						CopyEditorActionDelegate copyEditorActionDelegate = new CopyEditorActionDelegate();
						copyEditorActionDelegate.setActiveEditor(this,
								ExtendedQueryEditor.this);
						copyEditorActionDelegate.run(this);
						return;

					}
				};
				copyAction.setEnabled(true);
				copyAction.setActionDefinitionId("org.eclipse.ui.edit.copy");
				manager.add(copyAction);

				Object firstElement = selection1.getFirstElement();
				if (firstElement instanceof IHasPublicUrl) {
					addCopyURL(manager, firstElement);
				} else {
					if (firstElement instanceof IWorkingCopy) {
						IWorkingCopy copy = (IWorkingCopy) firstElement;
						Object original = copy.getOriginal();
						if (original instanceof IHasPublicUrl) {
							addCopyURL(manager, original);
						} else {
							System.err.println("#####-COPY_URL: "
									+ firstElement.getClass()
											.getCanonicalName()
									+ " !instanceof IHasPublicUrl");
						}
					} else {
						System.err.println("#####-COPY_URL: "
								+ firstElement.getClass().getCanonicalName()
								+ " !instanceof IHasPublicUrl");
					}

				}
				if (selection1.getFirstElement() instanceof GroupNode) {
					GroupNode node = (GroupNode) selection1.getFirstElement();

					MenuManager subManager = new MenuManager(
							"Group children by");

					IRealmView query = copy;
					String mn = query.getSettings().get(node.getLongString());
					Collection<IViewGrouping> groupings = query.getParent()
							.getQueryProvider().getGroupings();
					for (Iterator<IViewGrouping> iterator = groupings
							.iterator(); iterator.hasNext();) {
						IViewGrouping viewGrouping = (IViewGrouping) iterator
								.next();
						ChangeNodeGroupingAction action = new ChangeNodeGroupingAction(
								(GroupNode) (selection1.getFirstElement()),
								viewGrouping, viewer, ExtendedQueryEditor.this);
						action.setEnabled(true);
						action.setText(viewGrouping.getLabel());
						if (viewGrouping.getId().equals(mn)) {
							action.setChecked(true);
						}
						subManager.add(action);
					}
					manager.add(subManager);
					if (provider.getView().getSettings()
							.get(node.getLongString()) != null) {
						IAction disableAction = new ChangeNodeGroupingAction(
								(GroupNode) (selection1.getFirstElement()),
								null, viewer, ExtendedQueryEditor.this);
						disableAction.setEnabled(true);
						disableAction.setText("Disable grouping");
						manager.add(disableAction);
					}
				}
				if (!selection1.isEmpty()) {
					Action filterAction = new FilterBySelectionAction(
							selection1, ExtendedQueryEditor.this.copy,
							ExtendedQueryEditor.this);
					filterAction.setText("Filter by selection");
					manager.add(filterAction);
					FilterExceptSelectionAction filterExceptAction = new FilterExceptSelectionAction(
							selection1, ExtendedQueryEditor.this.copy,
							ExtendedQueryEditor.this);
					filterExceptAction.setText("Filter except selection");
					manager.add(filterExceptAction);
				}

				manager.add(new Separator("create"));

//				NewActionsContributor.contribute(copy.getParent(), selection1, //TODO new actions contribution
//						manager);
				boolean hasCanDelete = false;
				for (Object o : selection1.toArray()) {
					if (o instanceof ICanDelete) {
						ICanDelete s = (ICanDelete) o;
						if (s.canDelete()) {
							hasCanDelete = true;
						}
					}
				}
				if (hasCanDelete) {
					manager.add(new DeleteAction(
							selection1));
				}
				PropertyBasedMenuContributor.contribute(manager,
						new StructuredSelection(selection1.toList()));
				manager.add(new Separator());
				for (IAction a : optionsAction) {
					manager.add(a);
				}
			}
		});
		pManager.setRemoveAllWhenShown(true);
		Menu createContextMenu = pManager
				.createContextMenu(viewer.getControl());

		viewer.getControl().setMenu(createContextMenu);
		ColoredViewersManager.install(viewer);
		viewer.setSorter(new QueryViewerSoerter());
		TreeColumnLayout layout = new TreeColumnLayout();
		layout.setColumnData(titleColumn, new ColumnWeightData(1));
		parent.setLayout(layout);
		for (ColumnConfiguration ca : copy.columns()) {
			Column createColumn = createColumn(10, ca);
			addColumn(createColumn);
		}
		viewer.setInput(copy);
		String string = copy.getSettings().get(IRealmView.FOCUS_ON);
		if (string != null) {
			GroupNode resolve = provider.resolve(string);
			if (resolve != null) {
				setInto(resolve);
				updatePartTitle();
			}
		}
		viewer.addOpenListener(new IOpenListener() {
			public void open(OpenEvent event) {
				Object firstElement = ((IStructuredSelection) event
						.getSelection()).getFirstElement();
				doOpen(firstElement);
			}
		});
		if (getSite() != null) {
			getSite().registerContextMenu((MenuManager) pManager, viewer);
			getSite().setSelectionProvider(viewer);
		}
		DndUtil.addTextDragSource(viewer);
		createAdditionalActions();
		initActionStates();
		// appendLabels( copy);
	}

	protected abstract UniversalLabelProvider<Object> createLabelProvider(
			ExtendedQueryEditor extendedQueryEditor);

	protected void createAdditionalActions() {
		//Do nothing; Override if needed
	}

	protected void initActionStates() {
		//do nothing; Override if needed
	}

	protected ISelection convertSelection(ISelection oldSelection) {
		TreeSelection ts = (TreeSelection) oldSelection;
		TreePath[] paths = ts.getPaths();
		ArrayList<TreePath> newPaths = new ArrayList<TreePath>();
		GroupingContentProvider m = (GroupingContentProvider) viewer
				.getContentProvider();
		for (TreePath p : paths) {
			TreePath pa = m.map(p);
			if (pa != null) {
				newPaths.add(pa);
			}
		}
		return new TreeSelection(
				newPaths.toArray(new TreePath[newPaths.size()]));
	}

	protected void customizeActionBars(final UndoActionHandler undoActionHandler) {
		IActionBars actionBars = getEditorSite().getActionBars();
		actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(),
				undoActionHandler);
		final RedoActionHandler redoActionHandler = new RedoActionHandler(
				this.getEditorSite(), new ObjectUndoContext(this));
		redoActionHandler
				.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO);
		actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(),
				redoActionHandler);
		actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(),
				new Action("Copy") {
					{
						setActionDefinitionId(ActionFactory.COPY.getCommandId());
					}

					public void run() {
						CopyEditorActionDelegate copyEditorActionDelegate = new CopyEditorActionDelegate();
						copyEditorActionDelegate.setActiveEditor(this,
								ExtendedQueryEditor.this);
						copyEditorActionDelegate.run(this);
					}

				});
		actionBars.updateActionBars();
		getEditorSite().getActionBars().updateActionBars();
	}

	private void setInto(GroupNode resolve) {
		if (resolve.getParent() != null) {
			setInto(resolve.getParent());
		}
		drillDown.goInto(resolve);
	}

	protected void updatePartTitle() {
		StringBuilder bld = new StringBuilder();
		bld.append(getEditorInput().getName());
		Object input = viewer.getInput();
		if (input instanceof GroupNode) {
			GroupNode q = (GroupNode) input;
			copy.put(IRealmView.FOCUS_ON, q.getMemento());
			bld.append(" ");
			bld.append(q.getLongString());
		} else {
			copy.put(IRealmView.FOCUS_ON, null);
		}
		setPartName(bld.toString());
	}

	public void setupGrouping(IViewGrouping p) {
		copy.setCurrentGrouping(p);
		firePropertyChange(PROP_DIRTY);
		provider.setFirstGrouping(p);
		viewer.refresh();
	}

	public void setupSecondGrouping(IViewGrouping p) {
		copy.setSecondLevelGrouping(p);
		firePropertyChange(PROP_DIRTY);
		provider.setSecondGrouping(p);
		viewer.refresh();
	}

	protected void searchChanged() {
		viewer.getControl().redraw();
	}

	public void setCurrentSorting(Object data, boolean inverse) {
		super.setCurrentSorting(data, inverse);
		viewer.refresh();
		ColumnConfiguration m = (ColumnConfiguration) data;
		if (m == null) {
			viewer.getTree().setSortColumn(titleColumn);
			viewer.getTree().setSortDirection(inverse ? SWT.DOWN : SWT.UP);
			return;
		}
		for (TreeColumn c : viewer.getTree().getColumns()) {
			Column n = (Column) c.getData();
			if (n != null) {
				if (n.getId().equals(m.getId())) {
					viewer.getTree().setSortColumn(c);
					viewer.getTree().setSortDirection(
							inverse ? SWT.DOWN : SWT.UP);
				}
			}
		}
	}

	boolean sch;

	protected void editorRealmChanged() {
		if (viewer == null) {
			return;
		}
		if (sch) {
			return;
		}

		final Control control = viewer.getControl();
		if (control == null)
			return;
		sch = true;
		control.getDisplay().asyncExec(new Runnable() {

			public void run() {
				sch = false;
				firePropertyChange(PROP_DIRTY);
				if (control.isDisposed()) {
					return;
				}

				control.setRedraw(false);
				try {
					TreePath[] expandedTreePaths = viewer
							.getExpandedTreePaths();
					if (viewer.getInput() instanceof GroupNode) {
						provider.refreshNode();
					}
					boolean cellEditorActive = viewer.isCellEditorActive();
					viewer.refresh(true);
					if (cellEditorActive) {
						viewer.editElement(lastElement, lastEdit);
					}
					TreePath[] l2 = viewer.getExpandedTreePaths();
					HashSet<TreePath> p = new HashSet<TreePath>();
					p.addAll(Arrays.asList(expandedTreePaths));
					p.addAll(Arrays.asList(l2));
					viewer.setExpandedTreePaths(p.toArray(new TreePath[p.size()]));
					if (provider.contents.length <= EXPAND_ITEM_COUNT) {
						viewer.expandAll();
					}
					viewer.getControl().redraw();
				} finally {
					control.setRedraw(true);
				}

			}
		});
	}

	protected void removeColumn(Column m1) {
		for (Column c : activeColumns) {
			if (c.getId().equals(m1.getId())) {
				activeColumns.remove(c);
				break;
			}
		}

		for (TreeColumn t : viewer.getTree().getColumns()) {
			Column data = (Column) t.getData();
			if (data != null && data.getId().equals(m1.getId())) {
				t.dispose();
			}
		}
		if (activeColumns.size() == 1) {
			TreeColumnLayout f = (TreeColumnLayout) viewer.getTree()
					.getParent().getLayout();
			f.setColumnData(titleColumn, new ColumnWeightData(1));
			viewer.getTree().setHeaderVisible(false);

		}
		viewer.getTree().getParent().layout();
	}

	protected Collection<? extends Column> getColumns() {
		return new ArrayList<Column>(activeColumns);
	}

	protected Control getControl() {
		return viewer.getControl();
	}

	int lastEdit = -1;
	Object lastElement;

	protected void addColumn(final Column column4) {
		TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer,
				SWT.LEFT);
		IBaseLabelProvider labelProvider = viewer.getLabelProvider();
		treeViewerColumn.setLabelProvider((CellLabelProvider) labelProvider);
		final TreeColumn treeColumn = treeViewerColumn.getColumn();
		treeColumn.setText(column4.getCaption());

		ColumnEditingSupport s = new ColumnEditingSupport(column4, viewer) {

			ViewerCell lCell;

			protected void initEditor(CellEditor pcellEditor, ViewerCell cell) {
				lCell = cell;
				super.initEditor(pcellEditor, cell);
			}

			protected void moveDown() {
				ViewerCell neighbor = lCell
						.getNeighbor(ViewerCell.BELOW, false);
				if (neighbor != null && neighbor.getElement() != null) {
					doEdit(viewer, neighbor.getElement());
				}
			}

			protected void doEdit(ColumnViewer tableViewer, Object el) {
				lastElement = el;
				lastEdit = this.columnIndex;
				super.doEdit(tableViewer, el);
			}

			public void setValue(Object element, Object value) {
				if (element instanceof GroupNode) {
					return;
				}
				IWorkingCopy copy2 = copy.copy(element);
				IProperty property = provider.provider.getProperty(element,
						column4.getId());
				Binding bnd = new Binding(copy2, property, null);
				bnd.setValue(value, null);
				bnd.commit();
				bnd.dispose();
			}

			protected void moveUp() {
				ViewerCell neighbor = lCell
						.getNeighbor(ViewerCell.ABOVE, false);
				if (neighbor != null && neighbor.getElement() != null) {
					doEdit(viewer, neighbor.getElement());
				}
			}

		};

		treeViewerColumn.setEditingSupport(s);
		treeColumn.setToolTipText(column4.getDescription());
		treeColumn.setImage(ImageManager.getImage(column4.getImage()));
		treeColumn.setData(column4);
		treeColumn.addSelectionListener(new SelectionListener() {

			public void widgetSelected(SelectionEvent e) {

				for (ColumnConfiguration m : copy.columns()) {
					if (m.getId().equals(column4.getId())) {
						{
							if (viewer.getTree().getSortColumn() == treeColumn) {
								// inverse sort direction;
								boolean down = viewer.getTree()
										.getSortDirection() == SWT.UP;
								setCurrentSorting(m, down);

							} else {
								setCurrentSorting(m, false);
							}
						}
					}
				}
			}

			public void widgetDefaultSelected(SelectionEvent e) {

			}
		});
		if (column4.getId().equals(currentSorting)) {
			viewer.getTree().setSortColumn(treeColumn);
			viewer.getTree().setSortDirection(sortInverse ? SWT.DOWN : SWT.UP);
		}
		TreeColumnLayout m = (TreeColumnLayout) viewer.getTree().getParent()
				.getLayout();
		m.setColumnData(treeColumn, column4.getLayoutData());
		activeColumns.add(column4);
		viewer.getTree().getParent().layout();

		viewer.getTree().setHeaderVisible(true);
	}

	protected void doOpen(Object firstElement) {
		if (firstElement instanceof IWorkingCopy) {
			IWorkingCopy m = (IWorkingCopy) firstElement;
			firstElement = m.getOriginal();
		}
		Binding bnd = new Binding(firstElement);
		WidgetRegistry.getInstance().showWidget(bnd);
		bnd.dispose();
	}

	protected void fireDirty() {
		firePropertyChange(PROP_DIRTY);
	}

	public abstract void customize(Object document);

	public IWorkingCopy copy(Object obj) {
		return copy.copy(obj);
	}

	public IPropertyProvider provider() {
		return copy.getParent().getQueryProvider().provider();
	}

	public IRealmView getCopy() {
		return copy;
	}

	public ISelection getSelection() {
		return viewer.getSelection();
	}

	public ISelectionProvider getSelectionProvider() {
		return viewer;
	}

	public void makeDirty() {
		persistCopySettings();
		firePropertyChange(PROP_DIRTY);
	}

	/**
	 * @param manager
	 * @param selection1
	 */
	private void addCopyURL(IMenuManager manager, final Object firstElement) {
		IAction copyAction1 = new Action("Copy Url", Action.AS_PUSH_BUTTON) {
			public void run() {
				Clipboard clip = getClipboard();
				IHasPublicUrl utl = (IHasPublicUrl) firstElement;
				if (clip != null && !clip.isDisposed()) {
					TextTransfer transfer = TextTransfer.getInstance();
					Transfer[] tr = new Transfer[] { transfer };
					clip.setContents(new String[] { utl.getUrl() }, tr);
				}
				return;

			}
		};
		copyAction1.setEnabled(true);
		manager.add(copyAction1);
	}

	public AbstractRealmView getState() {
		return (AbstractRealmView) copy;
	}

	public void setState(AbstractRealmView shortV) {
		((AbstractRealmView) copy).updateFiltersAndGrouping(shortV);

		BooleanFilter[] iF = getInternalFilters();
		if (iF != null) {
			for (BooleanFilter f : iF) {
				((AbstractRealmView) copy).usedQuickFilters().add(f);
			}
		}

		provider.setFirstGrouping(copy.getCurrentGrouping());
		provider.setSecondGrouping(copy.getSecondLevelGrouping());
		// justUpdateStates(copy);
		firePropertyChange(PROP_DIRTY);
		fireIRealmChangeD();
	}

	/**
	 * 
	 */
	protected void alert(String message) {
		Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
				.getShell();
		MessageDialog.openError(shell, "Error", message);
	}

	protected BooleanFilter[] getInternalFilters() {
		return null;
	}
}
